package com.example.myyunpan.Controller;


import com.example.myyunpan.annotation.GlobalIntercepter;
import com.example.myyunpan.annotation.VerifyParam;
import com.example.myyunpan.component.RedisComponent;
import com.example.myyunpan.entity.config.AppConfig;
import com.example.myyunpan.entity.constants.Constants;
import com.example.myyunpan.entity.domain.UserInfo;
import com.example.myyunpan.entity.dto.CreateImageCode;
import com.example.myyunpan.entity.dto.SessionWebUserDto;
import com.example.myyunpan.entity.enums.ResponseCodeEnum;
import com.example.myyunpan.entity.enums.VerifyRegexEnum;
import com.example.myyunpan.entity.vo.ResponseVO;
import com.example.myyunpan.exception.BusinessException;
import com.example.myyunpan.service.EmailCodeService;
import com.example.myyunpan.service.UserInfoService;
import com.example.myyunpan.utils.MyFileUtils;
import com.example.myyunpan.utils.StringTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@RestController("accountController")
public class AccountController {

    @Autowired
    private EmailCodeService emailCodeService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private MyFileUtils myFileUtils;

    @Autowired
    private RedisComponent redisComponent;

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AccountController.class);

    /**
     * 验证码
     *
     * @param response
     * @param session
     * @param type
     * @throws IOException
     * 根据工具类生成验证码，并保存到session中，根据type来判断是邮箱验证码还是图片验证码
     */
    @RequestMapping(value = "/checkCode")
    public void checkCode(HttpServletResponse response, HttpSession session, Integer type) throws
            IOException {
        logger.info("=====================开启日志===================");
        CreateImageCode vCode = new CreateImageCode(130, 38, 5, 10);
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        String code = vCode.getCode();
//        根据type来判断是邮箱验证码还是图片验证码，保存到session中
        if (type == null || type == 0) {
//            登陆时候的图片验证码
            session.setAttribute(Constants.CHECK_CODE_KEY, code);
        } else {
//            发送邮箱的验证码
            session.setAttribute(Constants.CHECK_CODE_KEY_EMAIL, code);
        }
        vCode.write(response.getOutputStream());
    }


    /**
     * @return com.example.myyunpan.entity.vo.ResponseVO
     * @param @param session
    	* @param email
    	* @param checkCode
    	* @param type
     * @author znk
     * @date 2024/10/26 10:25
     * 发送邮箱验证码
     */
    @RequestMapping(value = "/sendEmailCode")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO sendEmailCode(HttpSession session,
                                    @VerifyParam(regex = VerifyRegexEnum.EMAIL,required = true) String email,
                                    @VerifyParam(required = true) String checkCode,
                                    @VerifyParam(required = true) Integer type) {
        try {
//            判断图片验证码是否正确
            if(!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY_EMAIL))){
                throw new BusinessException(ResponseCodeEnum.CODE_1000);
            }
            emailCodeService.sendEmailCode(email,type);
            return ResponseVO.success();
        } finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY_EMAIL);
        }
    }

    /**
     * @return com.example.myyunpan.entity.vo.ResponseVO
     * @param @param session
    	* @param email
    	* @param nickName
    	* @param password
    	* @param checkCode
    	* @param emailCode
     * @author znk
     * @date 2024/10/28 11:32
     * 用户注册
     */
    @RequestMapping("/register")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO register(HttpSession session,
                               @VerifyParam(required = true,regex = VerifyRegexEnum.EMAIL) String email,
                               @VerifyParam(required = true) String nickName,
                               @VerifyParam(required = true,regex = VerifyRegexEnum.PASSWORD,min = 8,max = 18) String password,
                               @VerifyParam(required = true) String checkCode,
                               @VerifyParam(required = true) String emailCode
                               ){
        try{
            if(!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))){
                throw new BusinessException(ResponseCodeEnum.CODE_1000);
            }
            userInfoService.register(email,nickName,password,emailCode);
            return ResponseVO.success();
        }finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);
        }
    }

    /**
     * @return com.example.myyunpan.entity.vo.ResponseVO
     * @param @param session
    	* @param request
    	* @param email
    	* @param password
    	* @param checkCode
     * @author znk
     * @date 2024/10/28 11:33
     * 用户登陆
     */
    @RequestMapping("/login")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO login(HttpSession session, HttpServletRequest request,
                               @VerifyParam(required = true) String email,
                               @VerifyParam(required = true) String password,
                               @VerifyParam(required = true) String checkCode
    ){
        try{
            if(!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))){
                throw new BusinessException(ResponseCodeEnum.CODE_1000);
            }
            SessionWebUserDto sessionwebuserdto = userInfoService.login(email, password);
//            将用户信息保存到session中
            session.setAttribute(Constants.SESSION_KEY,sessionwebuserdto);
            return ResponseVO.success(sessionwebuserdto);
        }finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);
        }
    }

    /**
     * @return com.example.myyunpan.entity.vo.ResponseVO
     * @param @param session
    	* @param email
    	* @param password
    	* @param checkCode
    	* @param emailCode
     * @author znk
     * @date 2024/10/28 11:33
     * 忘记密码
     */
    @RequestMapping("/resetPwd")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO resetPwd(HttpSession session,
                               @VerifyParam(required = true,regex = VerifyRegexEnum.EMAIL) String email,
                               @VerifyParam(required = true,regex = VerifyRegexEnum.PASSWORD,min = 8,max = 18) String password,
                               @VerifyParam(required = true) String checkCode,
                               @VerifyParam(required = true) String emailCode){
        try{
            if(!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))){
                throw new BusinessException(ResponseCodeEnum.CODE_1000);
            }
            userInfoService.resetPwd(email,password,emailCode);
            return ResponseVO.success();
        }finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);
        }
    }

    /**
     * @return void
     * @param @param response
    	* @param session
    	* @param userId
     * @author znk
     * @date 2024/10/29 15:11
     * 获取头像
     */
    @RequestMapping("/getAvatar/{userId}")
    @GlobalIntercepter(checkParams = true)
    public void getAvatar(HttpServletResponse response,HttpSession session, @VerifyParam(required = true) @PathVariable("userId") String userId){

//        图像存放文件夹路径
            String avatarFolderName = Constants.FILE_FOLDER_FILE+Constants.FILE_FOLDER_AVATAR_NAME;
//      判断文件夹是否存在，如果不存在就创建
            File file1 = new File(appConfig.getProjectFolder()+avatarFolderName);
            if(!file1.exists()){
                file1.mkdirs();
            }
//        图像路径.jpg
            String avatarPath = appConfig.getProjectFolder() + avatarFolderName + userId+ Constants.AVATAR_SUFFIX;
            File file = new File(avatarPath);
//            判断图像是否存在
            if(!file.exists()){
//                判断默认头像是否存在
                if(!new File(appConfig.getProjectFolder()+avatarFolderName+Constants.AVATAR_DEFUALT).exists()){
                    myFileUtils.printNoDefaultImage(response);
                    return;
                }
                avatarPath=appConfig.getProjectFolder()+avatarFolderName+Constants.AVATAR_DEFUALT;
            }
            response.setContentType("image/jpg");
            myFileUtils.readFile(response, avatarPath);
    }

    @RequestMapping("/getUserInfo")
    @GlobalIntercepter(checkParams = true)
    public ResponseVO getUserInfo(HttpSession session){
        SessionWebUserDto sessionwebuserdto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        return ResponseVO.success(sessionwebuserdto);
    }

    @RequestMapping("/getUseSpace")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO getUseSpace(HttpSession session){
        SessionWebUserDto sessionwebuserdto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        return ResponseVO.success(redisComponent.getUserSpaceUser(sessionwebuserdto.getUserId()));
    }

    @RequestMapping("/logout")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO logout(HttpSession session){
        session.invalidate();
        return ResponseVO.success();
    }

    /**
     * @return
     * @param @param null
     * @author znk
     * @date 2024/10/29 15:25
     * 更新用户头像
     */
    @RequestMapping("/updateUserAvatar")
    @GlobalIntercepter(checkParams = true)
    public ResponseVO updateUserAvatar(HttpSession session, MultipartFile avatar){
        SessionWebUserDto sessionwebuserdto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        String baseFolder=appConfig.getProjectFolder()+Constants.FILE_FOLDER_FILE;
        File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);
        if(!targetFileFolder.exists()){
            targetFileFolder.mkdirs();
        }
        File file = new File(
                baseFolder +
                        Constants.FILE_FOLDER_AVATAR_NAME +
                        sessionwebuserdto.getUserId() +
                        Constants.AVATAR_SUFFIX);
        try{
            avatar.transferTo(file);
        }catch (Exception e){
            e.printStackTrace();
            return ResponseVO.fail(ResponseCodeEnum.CODE_500);
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setQqAvatar("");
        userInfoService.updateUserInfoByUserId(userInfo, sessionwebuserdto.getUserId());
        sessionwebuserdto.setAvatar(null);
        session.setAttribute(Constants.SESSION_KEY, sessionwebuserdto);
        return ResponseVO.success();
    }

    @RequestMapping("/updatePassword")
    @GlobalIntercepter(checkParams = true)
    public ResponseVO updatePassword(HttpSession session,
                                     @VerifyParam(required = true, regex = VerifyRegexEnum.PASSWORD, min = 8, max = 18) String password) {
        SessionWebUserDto sessionWebUserDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        UserInfo userInfo = new UserInfo();
        userInfo.setPassword(StringTools.encodeByMD5(password));
        userInfoService.updateUserInfoByUserId(userInfo, sessionWebUserDto.getUserId());
        return ResponseVO.success();
    }

    /**
     * qq登录流程：
     * 1.用户点击qq登录按钮，跳转到qq登录页面，有一个二维码，扫码用户登录成功之后，qq会返回code凭证，回调到我们指定的地址，并且携带code参数
     * 2.我们拿到code凭证之后，通过code凭证，请求qq服务器，获取accessToken，通过accessToken获取用户的openid，openid是唯一标识一个用户
     * 3.我们拿到openid之后，判断是否是第一次登录，如果是第一次登录，则跳转到注册页面，否则直接登录
     * 4.如果用户已经注册，则直接登录，并且返回用户信息
     */

    /**
     * QQ第三方登录
     * @param session
     * @param callbackUrl qq登录完成之后，回调返回的地址
     * @return
     * @throws UnsupportedEncodingException
     */
    @RequestMapping("/qqlogin")
    @GlobalIntercepter(checkParams = true,checkLogin = false)
    public ResponseVO qqLogin(HttpSession session, String callbackUrl) throws UnsupportedEncodingException {
        String state = StringTools.getRandomNumber(Constants.LENGTH_30);
        if(!StringTools.isEmpty(callbackUrl)){
            session.setAttribute(state,callbackUrl);
        }
        String url = String.format(appConfig.getQqUrlAuthorization(),
                appConfig.getQqAppId(),
                URLEncoder.encode(appConfig.getQqUrlRedirect(),"utf-8"),
                state);
        logger.info("qq登录地址:{}",url);
        return ResponseVO.success(url);
    }

    /**
     * QQ登录回调
     * @param session
     * @param code qq登录成功之后返回的一个code凭证(重要)
     * @param state 取回调地址的时候传的session的key,
     *              state自定义的字符串，
     *              被qq登录时候携带，并原封不动返回
     * @return
     */
    @RequestMapping("/qqlogin/callback")
    @GlobalIntercepter(checkLogin = false, checkParams = true)
    public ResponseVO qqLoginCallback(HttpSession session,
                                  @VerifyParam(required = true) String code,
                                  @VerifyParam(required = true) String state) {
        logger.info("qq登录回调，code:{},state:{}",code,state);
        SessionWebUserDto sessionWebUserDto = userInfoService.qqLogin(code);
        session.setAttribute(Constants.SESSION_KEY, sessionWebUserDto);
        Map<String, Object> result = new HashMap<>();
        result.put("callbackUrl", session.getAttribute(state));
        result.put("userInfo", sessionWebUserDto);
        return ResponseVO.success(result);
    }


}
